#
#  Copyright 2022 The Open Islands Authors. All Rights Reserved.
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#
import logging
import os
import sys
import traceback

from pyoi.rpc.rpc_client import RPCClient
from pyoi.runtime.types import RuntimeState, CommonResponse, RuntimeConfig
from pyoi.runtime_env import RuntimeENV
from pyoi.util.base_utils import current_timestamp
from pyoi.util.log_utils import getLogger, LoggerFactory, exception_to_trace_string

LOGGER = getLogger()


class BaseRuntime:
    def __init__(self):
        self.pid: int = os.getpid()
        self.start_time: int = current_timestamp()
        self.end_time: int = None
        self.elapsed: int = None
        self.runtime_state: RuntimeState = RuntimeState()
        self.runtime_config: RuntimeConfig = None
        self.heartbeat_interval: int = 5

    def init(self):
        RuntimeENV.init()
        RPCClient.init()
        LoggerFactory.set_directory(directory=RuntimeENV.LOG_DIR,
                                    parent_log_dir=os.path.dirname(os.path.dirname(RuntimeENV.LOG_DIR)),
                                    append_to_parent_log=True, force=True)
        LOGGER.info(f"{self.__class__.__name__}, pid: {self.pid}")
        LOGGER.info(f"log level: {logging.getLevelName(LoggerFactory.LEVEL)}")
        LOGGER.info("all runtime env:")
        for env in RuntimeENV.get_all():
            LOGGER.info(f"{env}: {os.getenv(env)}")
        self.runtime_config = RuntimeConfig(**self.pull_config())

    def start(self):
        code = 0
        message = "ok"
        try:
            self.init()
            self.run()
        except Exception as e:
            LOGGER.exception(e)
            traceback.print_exc()
            try:
                self.handle_exception()
            except Exception as e:
                LOGGER.exception(e)
            code = 1
            message = exception_to_trace_string(e)
        finally:
            self.end_time = current_timestamp()
            self.elapsed = self.end_time - self.start_time
            LOGGER.info(
                f"{self.__class__.__name__}, pid: {self.pid}, state: {self.runtime_state.state}, endtime: {self.end_time}, elapsed: {self.elapsed} ms, message: {message}")
            self.finally_do()
            sys.exit(code)

    def run(self):
        raise NotImplementedError

    def handle_exception(self):
        raise NotImplementedError

    def pull_config(self):
        rep: CommonResponse = RPCClient.get_config()
        if rep.if_success():
            LOGGER.info(rep.data)
            return rep.data
        else:
            raise Exception("get config failed")

    def finally_do(self):
        raise NotImplementedError
